#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <map>

#include "xunzip.h"
#include "basexml.h"
#include "docx2txt.h"

using namespace std;

typedef struct XlsxCell
{
	char type;	/// '\0', 's'
	string value;

	XlsxCell(){ type = '\0'; }

	XlsxCell(char _type, const char* _value)
	{
		type = _type;
		value = _value;
	}
}XlsxCell;

void AppendString(string& str, string& appended, const char* appendstr = "\r\n")
{
	if (str.empty())
	{
		str = appended;
	}
	else
	{
		str += string(appendstr) + appended;
	}
}

void getSub(BaseXml& basexml, xmlNodePtr xmlnode, string& retstr, const char* appendstr = "\r\n");
void getSub(BaseXml& basexml, xmlNodePtr xmlnode, string& retstr, const char* appendstr)
{
	if (xmlnode != NULL)
	{
		const char* nodename = basexml.GetNodeName(xmlnode);
		xmlNodePtr sub = xmlnode->xmlChildrenNode;
		while (sub != NULL)
		{
			const char* subnodename = basexml.GetNodeName(sub);
			if (strcmp(subnodename, "t") == 0)	/// <t>docx或xlsx的文本节点
			{
				string s = basexml.GetNodeText(sub);
				if (!s.empty())
					AppendString(retstr, s, "");
			}
			getSub(basexml, sub, retstr, appendstr);
			sub = sub->next;
		}
		if (strcmp(nodename, "p") == 0)	/// <p>docx的段落节点
		{
			retstr += "\r\n";
		}
	}
}

std::string docx2txt(char* psrc, unsigned long srclen)
{
	std::string strret = "";
	char* pdst = new char[MAX_BUFFER_LENGTH];
	int dstlen = MAX_BUFFER_LENGTH;
	HZIP hz = OpenZip(psrc, srclen, ZIP_MEMORY);
	if (hz)
	{
		ZIPENTRY ze;
		GetZipItem(hz, -1, &ze);
		int numitems=ze.index;

		for (int zi=0; zi<numitems; zi++)
		{
			dstlen = MAX_BUFFER_LENGTH;
			memset(pdst, 0, dstlen);
			ZIPENTRY info;
			GetZipItem(hz,zi,&info);
			if (strcmp(info.name, "word/document.xml") == 0)
			{
				ZRESULT zresult = UnzipItem(hz, zi, pdst, dstlen,ZIP_MEMORY);
				if (zresult!=ZR_OK && zresult!=ZR_MORE)
				{
					goto END;
				}

				BaseXml basexml;
				std::string strxml = pdst;
				memset(pdst, 0, MAX_BUFFER_LENGTH);
				dstlen = 0;
				if (basexml.readXML(strxml))
				{
					xmlNodePtr curNode;
					curNode = basexml.GetRootNode(); //确定文档根元素
					if (curNode)
					{
						curNode = basexml.GetChildNode(curNode,"body");
						if (curNode)
						{
							string retstr;
							getSub(basexml, curNode, retstr);
							strret = retstr;
							break;
						}
					}
				}
			}
		}

		CloseZip(hz);
	}

END:
	delete[] pdst;
	return strret;
}

bool getXlsxSharedStrings(std::string& strxml, std::vector<std::string>& resarr)
{
	BaseXml basexml;
	if (basexml.readXML(strxml))
	{
		xmlNodePtr rootNode = basexml.GetRootNode();	///确定文档根元素<sst>
		if (rootNode)
		{
			xmlNodePtr cell = rootNode->xmlChildrenNode;	/// <si>元素，代表一个单元格的内容
			while (cell != NULL)
			{
				string cellstr;
				getSub(basexml, cell, cellstr, "");
				resarr.push_back(cellstr);

				cell = cell->next;
			}
		}
	}
	return true;
}

bool getXlsxDataIndexs(std::string& strxml, std::vector<std::map<uint, XlsxCell>* >& resarr)
{
	BaseXml basexml;
	if (!basexml.readXML(strxml))
	{
		return false;
	}

	xmlNodePtr rootNode = basexml.GetRootNode(); /// 确定文档根元素<worksheet>
	if (rootNode == NULL)
	{
		return false;
	}

	xmlNodePtr dataNode = basexml.GetChildNode(rootNode, "sheetData");	/// 数据元素<sheetData>
	if (dataNode == NULL)
	{
		return false;
	}

	/// 获取单元格范围
	xmlNodePtr dimensionNode = basexml.GetChildNode(rootNode, "dimension");	/// 数据范围<dimension ref="Xm:Yn">
	if (dimensionNode == NULL)
	{
		return false;
	}
	string dimension = basexml.GetNodeAttr(dimensionNode, "ref");
	if (dimension.empty())
	{
		return false;
	}
	const char* tp = dimension.c_str();
	uint cellpos_left = 0;
	uint cellpos_right = 0;
	uint cellpos_top = 0;
	uint cellpos_bottom = 0;
	cellpos_left = (uint)((tp++)[0] - 'A');
	if (tp[0] >= 'A' && tp[0] <= 'Z')
		cellpos_left = cellpos_left * 26 + (uint)((tp++)[0] - 'A');
	cellpos_top = (uint)atoi(tp);
	tp = strchr(tp, ':');
	if (tp == NULL)
	{
		return false;
	}
	tp++;
	cellpos_right = (uint)((tp++)[0] - 'A');
	if (tp[0] >= 'A' && tp[0] <= 'Z')
		cellpos_right = cellpos_right * 26 + (uint)((tp++)[0] - 'A');
	cellpos_bottom = (uint)atoi(tp);
	//printf("====Dimension: (%u,%u:%u,%u)\n", cellpos_left, cellpos_top, cellpos_right, cellpos_bottom);

	xmlNodePtr row = dataNode->xmlChildrenNode;	/// <row r="n">元素集合，n从1开始递增
	while (row != NULL)
	{
		map<uint, XlsxCell>* row_map = new map<uint, XlsxCell>;
		XlsxCell tmpcell('\0', "");
		for (uint i = cellpos_left; i <= cellpos_right; i++)
			(*row_map)[i] = tmpcell;
		resarr.push_back(row_map);

		xmlNodePtr node = row->xmlChildrenNode;	/// <c r="Xn或XXn" [t="s"]>元素集合；X|XX从A开始递增，超过Z后递增为AA并继续在右边位上递增；n从1开始递增
		for (; node != NULL; node = node->next)
		{
			string strpos = basexml.GetNodeAttr(node, "r");
			string strtype = basexml.GetNodeAttr(node, "t");
			if (strpos.empty())
				continue;
			uint cellpos = (uint)(strpos.c_str()[0] - 'A');
			if (strpos.c_str()[1] >= 'A' && strpos.c_str()[1] <= 'Z')
				cellpos = cellpos * 26 + (uint)(strpos.c_str()[1] - 'A');
			string strvalue;
			xmlNodePtr v = basexml.GetChildNode(node, "v");	/// <v>元素，保存的是数据对应字符串的索引（或真实数据）
			if (v)
			{
				strvalue = basexml.GetNodeText(v);
			}
			tmpcell.type = strtype.c_str()[0];
			tmpcell.value = strvalue;
			(*row_map)[cellpos] = tmpcell;
		}

		row = row->next;
	}
	/*
	for (uint i = 0; i < resarr.size(); i++)
	{
		for (map<uint, int>::iterator itor = resarr[i]->begin(); itor != resarr[i]->end(); itor++)
		{
			printf("%d\t", itor->second);
		}
		printf("\n");
	}
	*/
	return true;
}

std::string xlsx2txt(char* psrc, unsigned long srclen)
{
	std::string strret = "";
	char* pdst = new char[MAX_BUFFER_LENGTH];
	int dstlen = MAX_BUFFER_LENGTH;

	std::vector<std::string> string_arr;		/// 共享字符串数组
	vector<map<uint, XlsxCell>* > data_idx_matrix;	/// 索引矩阵，外面的维度是行，里面的维度是列

	HZIP hz = OpenZip(psrc, srclen, ZIP_MEMORY);
	if (hz)
	{
		ZIPENTRY ze;
		GetZipItem(hz, -1, &ze);
		int numitems = ze.index;

		/// 遍历xlsx文件中的xml文件列表
		for (int zi = 0; zi < numitems; zi++)
		{
			dstlen = MAX_BUFFER_LENGTH;
			memset(pdst, 0, dstlen);
			ZIPENTRY info;
			GetZipItem(hz, zi, &info);

			if (strncmp(info.name, "xl/worksheets/sheet1.xml", 24) == 0)	/// 这个只是保存字符串的分布信息
			{
				ZRESULT zresult = UnzipItem(hz, zi, pdst, dstlen, ZIP_MEMORY);
				if (zresult != ZR_OK && zresult != ZR_MORE)
				{
					goto END;
				}

				std::string strxml = pdst;
				getXlsxDataIndexs(strxml, data_idx_matrix);
			}
			else if (strncmp(info.name, "xl/sharedStrings.xml", 20) == 0)	/// 这个只是保存字符串的分布信息
			{
				ZRESULT zresult = UnzipItem(hz, zi, pdst, dstlen, ZIP_MEMORY);
				if (zresult != ZR_OK && zresult != ZR_MORE)
				{
					goto END;
				}
				string strxml = pdst;
				getXlsxSharedStrings(strxml, string_arr);	/// 获取所有的字符串数据并全部放入数组中
			}
		}

		/// 打印一下xlsx的解析结果（测试用）
		for (uint i = 0; i < data_idx_matrix.size(); i++)
		{
			string oneline;
			map<uint, XlsxCell>::iterator itor = data_idx_matrix[i]->begin();
			for (bool bFirstCell = true; itor != data_idx_matrix[i]->end(); itor++)
			{
				if (bFirstCell)
					bFirstCell = false;
				else
					oneline +="\t";
				if (itor->second.type == 's')
					oneline += string_arr[atoi(itor->second.value.c_str())].c_str();
				else
					oneline += itor->second.value.c_str();
			}
			oneline +="\n";

			strret += oneline;
		}

		CloseZip(hz);
	}

END:
	delete[] pdst;
	for (uint i = 0; i < data_idx_matrix.size(); i++)
	{
		if (data_idx_matrix[i])
			delete data_idx_matrix[i];
	}
	return strret;
}
